package com.tange.ai.iot.client.gnssa.play

import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.PorterDuff
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.util.Log
import android.view.Gravity
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.util.Consumer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.tange.ai.iot.client.gnssa.R
import com.tange.ai.iot.client.gnssa.databinding.ActivityDevicePlaybackBinding
import com.tange.base.toolkit.DateUtil
import com.tange.base.toolkit.Tips
import com.tange.base.toolkit.asTime
import com.tange.base.toolkit.asTimeWithoutDate
import com.tange.base.toolkit.gone
import com.tange.base.toolkit.onClicked
import com.tange.base.toolkit.ui
import com.tange.base.toolkit.visible
import com.tange.base.ui.design.BasicDialogRequest
import com.tange.core.device.manage.DeviceInfoQuery
import com.tange.core.media.render.DeviceMediaRender
import com.tange.core.media.source.impl.Speed
import com.tange.core.media.source.impl.cloud.CloudStorageMediaSource
import com.tange.core.media.source.impl.cloud.CloudVideoIndex
import com.tange.core.trouble.shooting.entry.DebuggingAssistant
//import com.tange.module.media.play.util.BitmapUtil
import com.tg.appcommon.android.TGLog
import java.io.File
import java.util.TimeZone

class CloudPlaybackActivity : AppCompatActivity() {

    companion object {
        private const val TAG = "CloudPlaybackActivity_"
        private const val PARAM_DEVICE_ID = "PARAM_DEVICE_ID"

        fun launch(context: Context, deviceId: String) {
            context.startActivity(Intent(context, CloudPlaybackActivity::class.java).apply {
                putExtra(PARAM_DEVICE_ID, deviceId)
            })
        }
    }

    private var albumPath = Environment.getExternalStorageDirectory()
        .toString() + File.separator + Environment.DIRECTORY_DCIM

    private lateinit var deviceId: String

    private lateinit var binding: ActivityDevicePlaybackBinding

    private lateinit var deviceMediaRender: DeviceMediaRender

    private lateinit var cloudStorageMediaSource: CloudStorageMediaSource

    private var timeZone = TimeZone.getDefault()

    private var isLandscape = false
    private var rendered = false

    private var cloudStorageFileExits = false

    private lateinit var listAdapter: ListAdapter

    private var speedPlayEnabled = false

    private var paused = false

    private var lastTimeStamp = ""

    private var currentVideoStart = 0L
    private var isSeeking = false

    // 表示是否正在下载一段云录像
    private var cloudStorageObtaining = false;

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityDevicePlaybackBinding.inflate(layoutInflater).apply {
            setContentView(root)
            supportActionBar?.hide()
            com.tange.ai.iot.client.gnssa.utils.Utils.setDarkStatusBar(this@CloudPlaybackActivity, Color.TRANSPARENT)
            listAdapter = ListAdapter()
            list.layoutManager = LinearLayoutManager(this@CloudPlaybackActivity, LinearLayoutManager.VERTICAL, false)
            list.adapter = listAdapter
            name.text = "云端录像"
        }

        deviceId = intent.getStringExtra(PARAM_DEVICE_ID)!!

        // 初始化调试助手，设置 顶部的 标题 为触发入口
        DebuggingAssistant.attach(this, binding.name).apply {
            deviceId = this@CloudPlaybackActivity.deviceId
        }

        cloudStorageMediaSource = CloudStorageMediaSource(this, deviceId).apply {
            observeFirstFrameReceived {
                TGLog.i(TAG, "[first-received] ")
            }
        }

        // 监听云端数据源的获取状态
        cloudStorageMediaSource.obtainStatusObserver = object : CloudStorageMediaSource.ObtainStatusObserver {

            override fun onDataSourceChanged(dataSource: CloudStorageMediaSource.DataSource) {
                cloudStorageObtaining = true;

                cloudStorageFileExits = false


                Log.i(TAG, "[ObtainStatus-Observer][onDataSourceChanged] ${dataSource.startTime?.asTime(timeZone)} ----> ${dataSource.endTime?.asTime(timeZone)}")
            }

            override fun onStart(time: Long) {
                Log.i(TAG, "[ObtainStatus-Observer][onStart] time = ${time.asTime(timeZone)}")
            }

            override fun onError(time: Long, code: Int, message: String) {
                Log.i(TAG, "[ObtainStatus-Observer][onError] time = ${time.asTime(timeZone)}, code = $code, message = $message ")
                binding.playTimestamp.text = "云录像丢失（${time.asTime(timeZone)}）"
                binding.playTimestamp.setTextColor(Color.RED)
            }

            override fun onSuccess(time: Long) {
                cloudStorageFileExits = true
                Log.i(TAG, "[ObtainStatus-Observer][onSuccess] time = ${time.asTime(timeZone)}")
            }

            override fun onComplete() {
                cloudStorageObtaining = false;

                Log.i(TAG, "[ObtainStatus-Observer][onComplete] ")

                // 可在此自动切换下一段录像播放
                if (!cloudStorageFileExits) {
                    BasicDialogRequest(this@CloudPlaybackActivity).apply {
                        setMessage("这段云录像全部丢失了，或者设备没有完成上传")
                        setPositiveText("知道了")
                        setPositiveOnClicked {
                            binding.loading.gone()
                            dismiss()
                        }
                    }.show()
                }
            }
        }

        // 创建媒体播放器
        deviceMediaRender = DeviceMediaRender(this, cloudStorageMediaSource).apply {

            // 将播放器示例绑定到UI上
            attach(binding.playerContainer, createCenterLayoutParams())

            // 监听首帧数据渲染回调
            observeFirstFrameRendered {
                Log.i(TAG, "[first-rendered] ")
                rendered = true
                binding.loading.gone()
            }
        }

        binding.seekbar.progressDrawable.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)
        binding.seekbar.thumb.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)

        binding.pauseResume.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.baseline_pause_circle_filled_24))
        binding.pauseResume.onClicked { pauseOrResume() }

        binding.loading.visible()
        binding.audio.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_baseline_volume_on_24))
        binding.audio.onClicked { switchAudio() }
        binding.screenShot.onClicked { screenshot() }
        binding.screenRecord.onClicked { screenRecord() }
        binding.fullScreen.onClicked { switchFullScreen() }
        binding.back.onClicked { finish() }
        binding.connect.onClicked {  }
        binding.speedPlay.onClicked { speedPlay() }

        // 监听播放的时间戳更新
        deviceMediaRender.onTimestampUpdate = Consumer {
            binding.playTimestamp.post {
                val current = DateUtil.getStrToTime(it, timeZone)
                if (lastTimeStamp == current) return@post
                lastTimeStamp = current
                TGLog.i(TAG, "[onTimestampUpdate] $current")

                binding.playTimestamp.text = "${current} ${timeZone.id}"
                binding.playTimestamp.setTextColor(Color.WHITE)

                if (currentVideoStart > 0 && !isSeeking) {
                    val process = it - currentVideoStart
                    if (process > 0) {
                        binding.seekbar.progress = process.toInt()
                    }
                }
            }
        }

        // 监听播放状态
        deviceMediaRender.renderStatusObserver = object : DeviceMediaRender.RenderStatusObserver {
            override fun onStart() {
                TGLog.i(TAG, "[Page-RenderStatusObserver][onStart] 有视频开始播放（可以隐藏加载动画）")

                ui {
                    binding.loading.gone()
                }
            }

            override fun onComplete() {

                paused = false

                if (!cloudStorageObtaining) {
                    TGLog.i(TAG, "[Page-RenderStatusObserver][onComplete] 这段录像完成了下载与播放")
                    binding.playTimestamp.post {
                        binding.playTimestamp.text = "这段录像完成了播放"
                    }

                    // 可在此自动切换下一段录像播放

                    BasicDialogRequest(this@CloudPlaybackActivity).apply {
                        setMessage("这段录像播完了")
                        setPositiveText("知道了")
                        setPositiveOnClicked {
                            binding.loading.gone()
                            dismiss()
                        }
                    }.show()
                } else {
                    TGLog.i(TAG, "[Page-RenderStatusObserver][onComplete] 队列无视频数据（应显示加载动画）")
                    binding.playTimestamp.post {
                        binding.playTimestamp.text = "队列无视频数据（应显示加载动画）"
                        binding.loading.visible()
                    }
                }
            }
        }

        binding.seekbar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
            override fun onProgressChanged(
                seekBar: SeekBar?,
                progress: Int,
                fromUser: Boolean,
            ) {
                val playPoint = currentVideoStart + binding.seekbar.progress
                binding.currentProgress.text = "松手以播放 ${playPoint.asTimeWithoutDate(timeZone)}"
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {
                binding.currentProgress.visible()
                isSeeking = true
            }

            override fun onStopTrackingTouch(seekBar: SeekBar?) {
                binding.currentProgress.gone()
                isSeeking = false
                if (currentVideoStart > 0) {
                    val playPoint = currentVideoStart + binding.seekbar.progress
                    seekToTime(playPoint)
                }
            }
        })

        DeviceInfoQuery.requireTimezone(deviceId) { resp ->

            // 先请求设备时区（若设备不存在出海、手机与设备分处不同时区的场景，可忽略此步骤）
            resp.data?.format()?.let {
                timeZone = it
            }

            ui {
                configureDate()
            }

            queryCloudPlayback(DateUtil.getTodayDate(timeZone))
        }
    }

    private fun seekToTime(playPoint: Long) {
        cloudStorageMediaSource.seek(playPoint)
        Tips.show("切换到：${playPoint.asTimeWithoutDate(timeZone)}")
        Log.i(TAG, "[OnSelected] seek to ${playPoint.asTime(timeZone)}")
        deviceMediaRender.reset()
    }

    private fun configureDate() {
        binding.days.visible()

        binding.day3.text = DateUtil.getTodayDate(timeZone)
        binding.day3.tag = DateUtil.getTodayDate(timeZone)

        binding.day1.text = DateUtil.getOldDate(-2, timeZone)
        binding.day1.tag = DateUtil.getOldDate(-2, timeZone)

        binding.day2.text = DateUtil.getOldDate(-1, timeZone)
        binding.day2.tag = DateUtil.getOldDate(-1, timeZone)

        binding.day3.onClicked {
            queryCloudPlayback(it.tag.toString())
            binding.day1.background =
                ContextCompat.getDrawable(it.context, R.drawable.day_rounded_bg_not_selected)
            binding.day2.background =
                ContextCompat.getDrawable(it.context, R.drawable.day_rounded_bg_not_selected)
            binding.day3.background =
                ContextCompat.getDrawable(it.context, R.drawable.day_rounded_bg_selected)
        }

        binding.day2.onClicked {
            queryCloudPlayback(it.tag.toString())
            binding.day1.background =
                ContextCompat.getDrawable(it.context, R.drawable.day_rounded_bg_not_selected)
            binding.day2.background =
                ContextCompat.getDrawable(it.context, R.drawable.day_rounded_bg_selected)
            binding.day3.background =
                ContextCompat.getDrawable(it.context, R.drawable.day_rounded_bg_not_selected)
        }

        binding.day1.onClicked {
            queryCloudPlayback(it.tag.toString())
            binding.day1.background =
                ContextCompat.getDrawable(it.context, R.drawable.day_rounded_bg_selected)
            binding.day2.background =
                ContextCompat.getDrawable(it.context, R.drawable.day_rounded_bg_not_selected)
            binding.day3.background =
                ContextCompat.getDrawable(it.context, R.drawable.day_rounded_bg_not_selected)
        }
    }

    private fun queryCloudPlayback(date: String) {
        Log.i(TAG, "[queryCloudPlayback] $date ...")
        CloudVideoIndex(deviceId).query(date) { resp ->

            ui {
                if (resp.success) {
                    if ((resp.data?.size ?: 0) > 0) {
                        resp.data?.let {
                            Log.i(TAG, "[queryCloudPlayback][$date] size = ${resp.data?.size ?: 0}")

                            val reversed = it.asReversed()
                            binding.list.visible()
                            binding.list.scrollToPosition(0)
                            listAdapter.refresh(reversed)

                            switchDataSource(reversed[0].toDataSource())

                            binding.emptyView.gone()
                        }
                    } else {
                        binding.list.gone()
                        binding.emptyView.visible()
                        binding.emptyView.text = "当日无云录像"
                    }
                } else {
                    if (resp.code == CloudVideoIndex.ERROR_NO_RECORD) {
                        binding.list.gone()
                        binding.emptyView.visible()
                        binding.emptyView.text = "当日无云录像"
                    } else {
                        binding.list.gone()
                        binding.emptyView.visible()
                        binding.emptyView.text = "获取云录像失败 ${resp.code}, ${resp.message}"
                    }

                    binding.loading.gone()
                }
            }

        }
    }

    // 暂停与恢复播放
    private fun pauseOrResume() {
        if (paused) {
            binding.pauseResume.setImageDrawable(
                ContextCompat.getDrawable(
                    this,
                    R.drawable.baseline_pause_circle_filled_24
                )
            )
            cloudStorageMediaSource.resume()
            deviceMediaRender.resume()
        } else {
            binding.pauseResume.setImageDrawable(
                ContextCompat.getDrawable(
                    this,
                    R.drawable.baseline_play_circle_filled_24
                )
            )
            cloudStorageMediaSource.pause()
            deviceMediaRender.pause()
        }
        paused = !paused
    }

    private fun speedPlay() {
        if (!speedPlayEnabled) {
            binding.speedPlay.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.baseline_fast_forward_24_enabled))
            cloudStorageMediaSource.setSpeed(Speed.x4)
            Tips.show("已开启 4 倍数播放")
        } else {
            binding.speedPlay.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.baseline_fast_forward_24))
            cloudStorageMediaSource.setSpeed(Speed.x1)
            Tips.show("已恢复 1 倍数播放")
        }

        speedPlayEnabled = !speedPlayEnabled
    }

    override fun onResume() {
        super.onResume()
        TGLog.i(TAG, "[onResume] ")
        deviceMediaRender.play(true)
        cloudStorageMediaSource.enableProduce(true)
    }

    override fun onPause() {
        super.onPause()
        TGLog.i(TAG, "[onPause] ")
        deviceMediaRender.play(false)
        cloudStorageMediaSource.enableProduce(false)
    }

    private fun createCenterLayoutParams() = FrameLayout.LayoutParams(
        FrameLayout.LayoutParams.MATCH_PARENT,
        FrameLayout.LayoutParams.MATCH_PARENT
    ).apply { gravity = Gravity.CENTER }

    private fun screenRecord() {
        if (deviceMediaRender.screenRecord().isStarted()) {
            val file = File(albumPath, "TG-${System.currentTimeMillis()}.mp4")
            deviceMediaRender.screenRecord().finish(file.absolutePath) {
                if (it) Tips.show("录屏已保存到 ${file.absolutePath}")
            }
            binding.screenRecord.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_baseline_videocam_24))
        } else {
            deviceMediaRender.screenRecord().start()
            binding.screenRecord.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_baseline_videocam_off_24))
            Tips.show("开始录屏，再次点击结束录屏")
        }
    }

    private fun switchAudio() {
        if (!deviceMediaRender.muted) {
            binding.audio.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_baseline_volume_off_24))
            deviceMediaRender.mute(true)
        } else {
            binding.audio.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_baseline_volume_on_24))
            deviceMediaRender.mute(false)
        }
    }

    private fun screenshot() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                this.requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 100)
            }
            Tips.show("需要存储权限")
            return
        }

        deviceMediaRender.screenshot()?.let {

            val file = File(albumPath, "TG-${System.currentTimeMillis()}.jpg")

//            BitmapUtil.saveBitmapToFile(file, it, Bitmap.CompressFormat.JPEG)

            if (file.exists()) {
                val intent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
                val uri = Uri.fromFile(file)
                intent.data = uri
                sendBroadcast(intent)
                Tips.show("截图已保存到 ${file.absolutePath}")
            }
        }
    }

    private fun switchFullScreen() {
        if (isLandscape) {
            binding.bottomLayout.visibility = View.VISIBLE
            binding.topBar.visibility = View.VISIBLE
            binding.opButtons.visibility = View.VISIBLE
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
            isLandscape = false
        } else {
            binding.bottomLayout.visibility = View.GONE
            binding.topBar.visibility = View.GONE
            binding.opButtons.visibility = View.GONE
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
            isLandscape = true
            binding.playerContainer.postDelayed({
                Tips.show("使用物理返回键退出全屏")
            }, 1000)
        }

        binding.playerContainer.post {
            deviceMediaRender.resize()
        }
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean =
        if (KeyEvent.KEYCODE_BACK == keyCode) {
            if (isLandscape) {
                switchFullScreen()
                true
            }
            else {
                finish()
                true
            }
        } else super.onKeyDown(keyCode, event)


    inner class ListAdapter : RecyclerView.Adapter<ViewHolder>() {
        private val apList: MutableList<CloudVideoIndex.Record> = java.util.ArrayList()
        fun refresh(list: List<CloudVideoIndex.Record>) {
            apList.clear()
            apList.addAll(list)
            notifyDataSetChanged()
        }

        override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
            val view: View = LayoutInflater.from(viewGroup.context)
                .inflate(R.layout.item_cloud_record_list, viewGroup, false)
            return ViewHolder(view)
        }

        override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
            val item = apList[position]
            var msg = ""

            val start = item.startTime ?: 0
            val end = item.endTime ?: 0

            val duration = end - start
            viewHolder.start.text = "${start.asTimeWithoutDate(timeZone)}  -  ${end.asTimeWithoutDate(timeZone)}   ${duration/1000}秒"
            viewHolder.itemView.setOnClickListener { view: View? ->
                binding.pauseResume.setImageDrawable(ContextCompat.getDrawable(view?.context!!, R.drawable.baseline_pause_circle_filled_24))
                paused = false
                switchDataSource(item.toDataSource())
            }
        }

        override fun getItemCount(): Int {
            return apList.size
        }
    }

    private fun switchDataSource(it: CloudStorageMediaSource.DataSource) {
        cloudStorageMediaSource.setDataSource(it)
        val start = (it.startTime ?: 0)

        currentVideoStart = start

        val end = (it.endTime ?: 0)
        binding.timelineSeekbar.visible()
        binding.seekbar.max = (end - start).toInt()

        binding.timelineStart.text = start.asTimeWithoutDate(timeZone)
        binding.timelineEnd.text = end.asTimeWithoutDate(timeZone)

        seekToTime(start)
    }

    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val start: TextView

        init {
            start = view.findViewById(R.id.start)
        }
    }
}